import { Application, IBoot } from 'egg';

const type = '[app]';

export default class AppBoot implements IBoot {
  private readonly app: Application;

  constructor(app: Application) {
    this.app = app;

    // 订阅 refresh_config 事件
    app.messenger.on('refresh_config', async (by) => {
      app.logger.info(type, 'start refresh config by', by);

      try {
        const ctx = app.createAnonymousContext();
        app.appConfig = await ctx.service.appConfig.get();
        app.logger.info(type, 'refresh config success');
      } catch (e) {
        app.logger.error(type, 'refresh config error', e);
      }
    });
  }

  configWillLoad() {
    // Ready to call configDidLoad,
    // Config, plugin files are referred,
    // this is the last chance to modify the config.

    const { app } = this;

    // 修改启动端口
    app.config.cluster = {
      listen: {
        port: this.app.config.m7Consul.service.port,
      },
    };
  }

  configDidLoad() {
    // Config, plugin files have loaded.
  }

  async didLoad() {
    // All files have loaded, start plugin here.
  }

  async willReady() {
    // All plugins have started, can do some thing before app ready.

    const { app } = this;

    try {
      // 除了在请求时可以获取 Context 实例之外
      // 在有些非用户请求的场景下我们需要访问 service / model 等 Context 实例上的对象
      // 我们可以通过 Application.createAnonymousContext() 方法创建一个匿名 Context 实例
      const ctx = app.createAnonymousContext();

      app.appConfig = await ctx.service.appConfig.get();
      app.logger.info(type, '获取配置成功');
    } catch (e) {
      app.logger.error(type, '获取配置失败', e);
      process.exit(-1);
    }

    // commonDB
    const connectCommonDB = async () => {
      try {
        this.app.commonDB = await this.app.m7Mongo.createInstanceAsync({
          host: this.app.appConfig.commonDbIp,
          port: this.app.appConfig.commonDbPort,
          name: this.app.appConfig.commonDbDbName,
          user: this.app.appConfig.commonDbUserName,
          password: this.app.appConfig.commonDbPassword,
          options: {
            authSource: 'admin',
            poolSize: this.app.appConfig.commonDbPoolSize,
            haInterval: this.app.appConfig.commonDbHaInterval,
          },
        });
        this.app.logger.info(type, '连接commonDB成功');
        return Promise.resolve();
      } catch (e) {
        this.app.logger.error(type, '连接commonDB失败', e);
        throw (e);
      }
    };

    // reportDB
    const connectReportDB = async () => {
      const readPreference = app.m7Consul.serviceInfo.version_tag === 'v-release' ? 'secondary' : 'secondaryPreferred';
      try {
        this.app.reportDB = await this.app.m7Mongo.createInstanceAsync({
          host: this.app.appConfig.reportDbIp,
          port: this.app.appConfig.reportDbPort,
          name: this.app.appConfig.reportDbDbName,
          user: this.app.appConfig.reportDbUserName,
          password: this.app.appConfig.reportDbPassword,
          options: {
            authSource: 'admin',
            poolSize: this.app.appConfig.reportDbPoolSize,
            haInterval: this.app.appConfig.reportDbHaInterval,
            readPreference,
          },
        });
        this.app.logger.info(type, '连接reportDB成功');
        return Promise.resolve();
      } catch (e) {
        this.app.logger.error(type, '连接reportDB失败', e);
        throw e;
      }
    };

    // ccRedis
    // const connectCcRedis = async () => {
    //   try {
    //     this.app.ccRedis = await this.app.m7Redis.createInstanceAsync({
    //       sentinels: [
    //         { host: this.app.appConfig.ccRedisSentinelHost, port: this.app.appConfig.ccRedisSentinelPort },
    //       ],
    //       name: 'master01',
    //       role: 'master',
    //       password: this.app.appConfig.ccRedisSentinelPwd,
    //     });
    //     this.app.logger.info(type, '连接redis成功');
    //     return Promise.resolve();
    //   } catch (e) {
    //     this.app.logger.error(type, '连接redis失败', e);
    //     throw e;
    //   }
    // };

    await Promise.all([
      connectCommonDB(),
      connectReportDB(),
      // connectCcRedis(),
    ]);
  }

  async didReady() {
    // Worker is ready, can do some things
    // don't need to block the app boot.
  }

  async serverDidReady() {
    // Server is listening.
    this.app.logger.info(type, '服务启动成功，监听端口', this.app.config.m7Consul.service.port);
    const ctx = this.app.createAnonymousContext();
    try {
    } catch (e) {
      ctx.logger.error('initMockData error', e);
    }
  }

  async beforeClose() {
    // Do some thing before app close.
  }
}
